#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <strings.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/epoll.h>

# define SERV_PORT 9527

void sys_err(const char *str)
{
    perror(str);
    exit(1);
}

//运用epoll创建服务器
int main(int argc, char *argv[])
{
	int lfd, cfd;
	int i ,j, fret;
	char buf[4096], clit_ip[1024];
	
	struct sockaddr_in	serv_addr, clit_addr;
	socklen_t	clit_addr_len;
	
	int nready, efd, res;
	struct epoll_event tep, ep[1024];//temp:epoll_cnl的参数 ep[1024]:epoll_wait的参数

	bzero(&serv_addr, sizeof(serv_addr));//将地址空间清零，即初始化，也可以用memset函数
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(SERV_PORT);//本地字节序转网络字节序
	serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);//任意可用ip地址

	lfd = socket(AF_INET,SOCK_STREAM,0);
	if(lfd == -1)
		sys_err("server socket create error");
	

	//设置端口复用
	int opt = 1;
	int ret = setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR,&opt, sizeof(opt));
	if(ret == -1)
		sys_err("setsocketopt  error");
	

	ret = bind(lfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr));
	if(ret == -1)
		sys_err("server listen error");
	
	ret = listen(lfd, 128);
	if(ret == -1){
		sys_err("server listen error");
	}

	efd = epoll_create(1024);//创建epoll红黑树
	if (efd == -1)
		sys_err("epoll create error");

	tep.events = EPOLLIN;
	tep.data.fd = lfd;
	res = epoll_ctl(efd, EPOLL_CTL_ADD, lfd, &tep);//将lfd及对应的结构体挂到树上
	if (res == -1)
		sys_err("epoll_ctl add lfd error");

	while(1){
		nready = epoll_wait(efd, ep, 1024, -1);//epoll_wait阻塞监听
		if (nready == -1)
			sys_err("epoll_wait error");
		
		for (i = 0; i < nready; i++){

			if(ep[i].data.fd == lfd){

				clit_addr_len = sizeof(clit_addr);//传入只用求一次，放在循环里会反复求
				cfd = accept(lfd, (struct sockaddr *)&clit_addr, &clit_addr_len) ;
				if(cfd == -1)
					sys_err("server accept error");
			
				printf("client %d connected\n", cfd);
				printf("client ip:%s, port:%d\n", 
						inet_ntop(AF_INET, &clit_addr.sin_addr.s_addr, clit_ip, sizeof(clit_ip)),
						ntohs(clit_addr.sin_port));

				tep.events = EPOLLIN;//将创建的cfd挂到树上
				tep.data.fd = cfd;
				res = epoll_ctl(efd, EPOLL_CTL_ADD, cfd, &tep);//将lfd及对应的结构体挂到树上
				if (res == -1)
				sys_err("epoll_ctl add cfd error");
			}
			else{  //不是lfd的情况

				fret = read(ep[i].data.fd , buf ,sizeof(buf));
				if (fret == 0){
					res = epoll_ctl(efd, EPOLL_CTL_DEL, ep[i].data.fd, NULL);//从epoll树上摘下
					if (res ==-1)
						sys_err("epoll_ctl delete cfd error");

					printf("client %d closed\n", ep[i].data.fd);
					close(ep[i].data.fd);
				}

				write(STDOUT_FILENO, buf ,fret);

				for(j = 0; j<fret; j++){
					buf[j] = toupper(buf[j]);//对数据进行操作			
				}
				write(ep[i].data.fd,buf,fret);
			}
		}
	}

	close(lfd);
	return 0;
}

